#ifndef __INPUT_INTERFACE_HEADER__
#define __INPUT_INTERFACE_HEADER__


class SystemEvents;

enum InputEventType
{
	INPUT_EVENT_KEY,
	INPUT_EVENT_MOUSE,
	INPUT_EVENT_TEXT,
};

namespace Mouse
{
	enum Button
	{
		BTN_LEFT		= 1,
		BTN_RIGHT		= 1<<1,
		BTN_CENTER		= 1<<2,
		BTN_WHEEL_UP	= 1<<3,
		BTN_WHEEL_DN	= 1<<4,
	};

}

struct InputEventKey
{
	int		scancode;
	bool	pressed;
};

struct InputEventMouse
{
	int		x,y;
	uint32	buttons;
};

struct InputEventText
{
	int character;
};


struct InputEvent
{
	InputEventType	type;
	union
	{
		InputEventKey	keyEvent;
		InputEventMouse	mouseEvent;
		InputEventText	textEvent;
	};

	InputEvent(InputEventType type) { this->type = type; }
};

class InputEventHandler
{
public:
	virtual bool HandleInputEvent(const InputEvent & event) = 0;
};

class InputManager
{
	friend class SystemEvents;
	InputManager();
	virtual ~InputManager();
public:

	//
	static InputManager* GetInstance()		{ return m_pInstance;				}	
	static void Initialize()				{ m_pInstance = new InputManager;	}	
	static void Finalize()					{ _SAFE_DELETE(m_pInstance);		}	

	//! Register input handler
	void RegisterInputHandler(InputEventHandler* handler);

	// Update frame
	void Update();
	void PostUpdate();

	// Keyboard state
	bool	GetKey(uint8 scancode)					{ return m_key[scancode]; }
	bool	GetAlt()								{ return m_key[VK_MENU]; }
	bool	GetCtrl()								{ return m_key[VK_CONTROL]; }
	bool	GetShift()								{ return m_key[VK_SHIFT]; }

	// One time triggers
	bool	GetOnKeyDown(uint8 scancode)			{ return m_key[scancode] && !m_lastKey[scancode]; }

	bool	GetMouseButton(Mouse::Button btn)		{ return (m_mouseButtons & btn) != 0; }
	bool	GetOnMouseButtonDown(Mouse::Button btn)	{ return ((m_mouseButtons & btn) != 0) && ((m_lastMouseButtons & btn) == 0); }
	bool	GetOnMouseButtonUp(Mouse::Button btn)	{ return ((m_mouseButtons & btn) == 0) && ((m_lastMouseButtons & btn) != 0); }
	bool	GetOnMouseDoubleClick(Mouse::Button btn){ return ((m_mouseButtonDC & btn) != 0); }
	int		GetMouseDeltaX()						{ return m_mouseX - m_mouseLastX; }
	int		GetMouseDeltaY()						{ return m_mouseY - m_mouseLastY; }
	int		GetMouseX()								{ return m_mouseX; }
	int		GetMouseY()								{ return m_mouseY; }

protected:
	static InputManager*			m_pInstance;
	std::vector<InputEventHandler*>	m_inputHandlers;
	bool							m_key[256];
	bool							m_lastKey[256];
	uint32							m_mouseButtons;
	uint32							m_lastMouseButtons;
	uint32							m_mouseButtonDC;	// doubleclicks
	int								m_mouseLastX;
	int								m_mouseLastY;
	int								m_mouseX;
	int								m_mouseY;

protected:
	inline void Send(const InputEvent & event)
	{
		for(size_t i=0;i<m_inputHandlers.size();i++)
			m_inputHandlers[i]->HandleInputEvent( event );
	}

	//! Windows message handler
	//! \detail Return false to stop forwarding the event to other event handlers
	bool WinEventHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
};

#define gInputManager	InputManager::GetInstance() 

#endif
